#pragma once

#ifndef ES_TCP_MAX_BUFFER    //TCP socket 最大接收 Buffer Size
#   define  ES_TCP_MAX_BUFFER    1024*16
#endif

#ifndef _WINDEF_
typedef unsigned char       BYTE;
#endif
// STL头文件定义
#include <string>
#include <queue>
#include <vector>
#include <deque>
#include <list>
#include <iostream>
#include <sstream>
#include <map>
#include <arpa/inet.h>
#include <iomanip>
using namespace std;

#if WIN32
typedef long long       int64_t;
#endif

#ifndef WIN32
#   define _atoi64 atoll
#endif

#define     SERVER_PACEKTVER    1
#define     PROTOL_HEADER_SIZE  8

/*
struct TPkgHeader //包头
{
    char  cmdConst[2]; //ES
    short cmd;
    short cVersion;
    short length; //body长度
};
*/


typedef unsigned long long __u64;
#define de_htonll(x) \
({ \
    __u64 __x = (x); \
    ((__u64)( \
    (__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \
    (__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \
    (__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \
    (__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) <<  8) | \
    (__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >>  8) | \
    (__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \
    (__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \
    (__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56) )); \
})


inline long long htonll(long long hvalue)
{
    //判断本机是大端还是小端
    short  i=20;
    if( htons(i) == i ) //本地是大端
    {
        return hvalue;
    } 
    else //本地是小端，需要转换
    {
        return (long long)de_htonll(hvalue);
    }
}

inline long long ntohll(long long nvalue)
{
    //判断本机是大端还是小端
    short  i=20;
    if( htons(i) == i ) //本地是大端
    {
        return nvalue;
    } 
    else //本地是小端，需要转换
    {
        return (long long)de_htonll(nvalue);
    }
}


inline string ESHexDumpImp(const void *pdata, unsigned int len)
{
        string outstr;
       if(pdata == 0 || len == 0)
        {
            return "";
        }
    
        int cnt = 0;
        int n = 0;
        int cnt2 = 0;
        stringstream  sstr;
        const char *data = (const char *)pdata;
        sstr<<"Address               Hexadecimal values                  Printable\n";
        sstr<<"-------  -----------------------------------------------  -------------\n";
        unsigned char buffer[20];
        unsigned int rpos = 0;

        while ( 1 )
        {
                if(len <= rpos)
                {
                        break;
                }
                if(len >= rpos + 16)
                {
                        memcpy(buffer, data + rpos, 16);
                        rpos += 16;
                        cnt = 16;
                }
                else
                {
                        memcpy(buffer, data + rpos, len - rpos);
                        cnt = len - rpos;
                        rpos = len;
                }
                if(cnt <= 0)
                {
                        outstr = sstr.str();
                        return outstr;
                }

                sstr << setw(7) << ( int ) rpos << "  ";

                cnt2 = 0;
                for ( n = 0; n < 16; n++ )
                {
                        cnt2 = cnt2 + 1;
                        if ( cnt2 <= cnt )
                        {
                                sstr << hex << setw(2) << setfill ( '0' ) <<  (unsigned int)buffer[n];
                        }
                        else
                        {
                                sstr << "  ";
                        }
                        sstr << " ";
                }

                sstr << setfill ( ' ' );

                sstr << " ";
                cnt2 = 0;
                for ( n = 0; n < 16; n++ )
                {
                        cnt2 = cnt2 + 1;
                        if ( cnt2 <= cnt )
                        {
                                if ( buffer[n] < 32 || 126 < buffer[n] )
                                {
                                        sstr << '.';
                                }
                                else
                                {
                                        sstr << buffer[n];
                                }
                        }
                }
                sstr << "\n";
                sstr << dec;
        }

        outstr = sstr.str();
        return outstr;
}



template <unsigned _buffer_size, unsigned _header_size>
class PacketBase
{
public:
    char *packet_buf(void)   {return m_strBuf;}
    unsigned packet_size(void)    {return m_nPacketSize;}
protected:
	PacketBase(void){}
    ~PacketBase(void){}
    enum
    {
        PACKET_HEADER_SIZE = _header_size,
        PACKET_BUFFER_SIZE = _buffer_size
    };
	unsigned  m_nPacketSize ; // 实际报文总长度
    unsigned  m_nBufPos;
    char m_strBuf[PACKET_BUFFER_SIZE];  // 报文包缓存

protected:
    ////////////////////////////////////////////////////////////////////////////////
    bool _copy(const void *pInBuf, unsigned nLen)
    {
        if(NULL==pInBuf || nLen > PACKET_BUFFER_SIZE){
            return false;
		}

        _reset();
        memcpy(m_strBuf, pInBuf, nLen);
        m_nPacketSize = nLen;
        //assert(m_nPacketSize>PACKET_HEADER_SIZE);
        return true;
    }
    ////////////////////////////////////////////////////////////////////////////////
    void _begin(short nCmdType, short cVersion)
    {
        _reset();
        _writeHeader("ES", sizeof(char)*2, 0);// 命令码

        short cmdType = htons(nCmdType);
        _writeHeader((char*)&cmdType, sizeof(short), 2);// 命令码
        
        short version = htons(cVersion);
        _writeHeader((char*)&version, sizeof(short), 4);       // 版本号
    }

    void _SetBegin(short nCmdType)
    {
        short cmdType = htons(nCmdType);
        _writeHeader((char*)&cmdType, sizeof(short), 2);// 命令码
    }
public:
    short GetCmdType(void)
    {
        short nCmdType;
        _readHeader((char*)&nCmdType, sizeof(short), 2);// 命令码
        return ntohs(nCmdType);
    }
    short GetVersion(void)
    {
        short c;
        _readHeader((char *)&c, sizeof(short), 4);  // 版本号
        return ntohs(c);
    }
    short GetBodyLength(void)
    {
        short nLen;
        _readHeader((char*)&nLen, sizeof(short), 6);// 包正文长度
        return ntohs(nLen);
    }

protected:
    void _end(unsigned /*sequence*/ = 0)
    {
        short nBody = m_nPacketSize - PACKET_HEADER_SIZE;
        short bodyLen = htons(nBody);
        _writeHeader((char*)&bodyLen, sizeof(short), 6);  // 包正文长度
    }

    /////////////////////////////////////////////////////////////////////////////////
    void _reset(void)
    {
        memset(m_strBuf, 0, PACKET_BUFFER_SIZE);
        m_nBufPos = PACKET_HEADER_SIZE;
        m_nPacketSize = PACKET_HEADER_SIZE;
    }
    // 取出一个变量
    bool _Read(char *pOut, unsigned nLen)
    {
        if((nLen + m_nBufPos) > m_nPacketSize )
            return false ;

        memcpy(pOut, m_strBuf + m_nBufPos, nLen);
        m_nBufPos += nLen;
        return true;
    }
    //取出变量并从包中移除
    bool _ReadDel(char *pOut, unsigned nLen)
    {
        if(!_Read(pOut, nLen)){
            return false;
		}
        memcpy(m_strBuf + m_nBufPos - nLen, m_strBuf + m_nBufPos, PACKET_BUFFER_SIZE - m_nBufPos);
        m_nBufPos -= nLen;
        m_nPacketSize -= nLen;
        _end();
        return true;
    }
    //读撤消
    void _readundo(unsigned nLen)
    {
        m_nBufPos -= nLen;
    }
    //读出当前POS位置的BUFFER指针
    char *_readpoint(unsigned nLen) //注意返回的是指针 请慎重使用string
    {
        if((nLen + m_nBufPos) > m_nPacketSize){
            return NULL; 
		}
        char *p = &m_strBuf[m_nBufPos];
        m_nBufPos += nLen;
        return p;

    }
    // 写入一个变量
    bool _Write(const char *pIn, unsigned nLen)
    {
        if( (nLen + m_nPacketSize) > PACKET_BUFFER_SIZE){
            return false ;
		}
        memcpy(m_strBuf+m_nPacketSize, pIn, nLen);
        m_nPacketSize += nLen;
        return true;
    }
    //插入一个变量
    bool _Insert(const char *pIn, unsigned nLen)
    {
        if((nLen + m_nPacketSize) > PACKET_BUFFER_SIZE){
            return false;
		}
        memcpy(m_strBuf+PACKET_HEADER_SIZE+nLen, m_strBuf+PACKET_HEADER_SIZE, m_nPacketSize-PACKET_HEADER_SIZE);
        memcpy(m_strBuf+PACKET_HEADER_SIZE, pIn, nLen);
        m_nPacketSize += nLen;
        _end();
        return true;
    }
    // 写入一个变量
    bool _writezero(void)
    {
        if((m_nPacketSize + 1) > PACKET_BUFFER_SIZE){
            return false ;
		}
        memset(m_strBuf+m_nPacketSize, '\0', sizeof(char)) ;
        m_nPacketSize ++;
        return true;
    }
    // readHeader
    void _readHeader(char *pOut, unsigned nLen, unsigned nPos)
    {
        if( nPos+nLen <= PACKET_HEADER_SIZE)
        {
            memcpy(pOut, m_strBuf+nPos, nLen) ;
        }
    }
    // writeHeader
    void _writeHeader(char *pIn, unsigned nLen, unsigned nPos)
    {
        if( nPos+nLen <= PACKET_HEADER_SIZE)
        {
            memcpy(m_strBuf+nPos, pIn, nLen) ;
        }
    }
};

template <unsigned BUFFER_SIZE, unsigned HEADER_SIZE=PROTOL_HEADER_SIZE>
class InputPacket: public PacketBase<BUFFER_SIZE, HEADER_SIZE>
{
public:
    typedef PacketBase<BUFFER_SIZE, HEADER_SIZE> base;

    int ReadInt(void)
    {
        //这里必需初始化
        int nValue = -1; 
        base::_Read((char*)&nValue, sizeof(int)); 
        return ntohl(nValue);
    } 

    short ReadShort(void)
    {
        short nValue = -1; 
        base::_Read((char*)&nValue, sizeof(short)); 
        return ntohs(nValue);
    }

    BYTE ReadByte(void)
    {
        BYTE nValue = -1; 
        base::_Read((char*)&nValue, sizeof(BYTE)); 
        return nValue;
    }

    int64_t ReadInt64(void)
    {
        int64_t nValue = -1; 
        base::_Read((char*)&nValue, sizeof(int64_t));
        return ntohll(nValue);
    }

    bool ReadString(char *pOutString, unsigned nMaxLen)
    {
        int nLen = ReadInt();
        if(nLen == -1){  //这里必需判断
            return false;
		}
        if(nLen > nMaxLen || nLen+base::m_nBufPos>base::m_nPacketSize )
        {
            base::_readundo(sizeof(unsigned));
            return false;
        }
        return base::_Read(pOutString, nLen);
    }

    char *ReadChar(void)
    {
        unsigned nLen = ReadInt();
        if(nLen == (unsigned)-1 || nLen+base::m_nBufPos>base::m_nPacketSize) {
			base::_readundo(sizeof(unsigned));
			return NULL;
		}
        return base::_readpoint(nLen);
    }

    bool ReadString(string &str)
    {
        char *p = ReadChar();
        str =  (p == NULL ? "" : p);
		return p != NULL;
    }

    int ReadBinary(char *pBuf, unsigned nMaxLen)
    {
        unsigned nLen = ReadInt();
        if(nLen == (unsigned)-1 || nLen > nMaxLen || nLen+base::m_nBufPos>base::m_nPacketSize )
        {
            base::_readundo(sizeof(unsigned));
            return -1;
        }
        if(base::_Read(pBuf, nLen)){
            return nLen ;
		}
        return 0;
    }
    void Reset(void)
    {
        base::_reset();
    }
    bool Copy(const void *pInBuf, unsigned nLen)
    {
        return base::_copy(pInBuf, nLen);
    }
};

template <unsigned BUFFER_SIZE, unsigned HEADER_SIZE=PROTOL_HEADER_SIZE>
class OutputPacket: public PacketBase<BUFFER_SIZE, HEADER_SIZE>
{
public:
    OutputPacket(void){}
public:
    typedef PacketBase<BUFFER_SIZE, HEADER_SIZE> base;

    bool WriteInt(int nValue)
    {
        int value = htonl(nValue);
        return base::_Write((char*)&value, sizeof(int));
    }

    bool WriteInt64(int64_t nValue)     
    {
        int64_t value = htonll(nValue);
        return base::_Write((char*)&value, sizeof(int64_t));
    }

    bool WriteByte(BYTE nValue)     
    {
        return base::_Write((char*)&nValue, sizeof(BYTE));
    }

    bool WriteShort(short nValue)
    {
        short value = htons(nValue);
        return base::_Write((char*)&value, sizeof(short));
    }

    //在正文首插入数据
    bool InsertInt(int nValue)
    {
        int value = htonl(nValue);
        return base::_Insert((char*)&value, sizeof(int));
    }

    bool InsertByte(BYTE nValue)    
    {
        return base::_Insert((char*)&nValue, sizeof(BYTE));
    }

    bool WriteString(const char *pString)
    {
        int nLen = (int)strlen(pString) ;
        WriteInt(nLen + 1) ;
        return base::_Write(pString, nLen) && base::_writezero();
    }

    bool WriteString(const string &strDate)
    {
        int nLen = strDate.size();
        WriteInt(nLen + 1) ;
        return base::_Write(strDate.c_str(), nLen) && base::_writezero();
    }

    bool WriteBinary(const char *pBuf, unsigned nLen)
    {
        WriteInt(nLen) ;
        return base::_Write(pBuf, nLen) ;
    }
    bool Copy(const void *pInBuf, unsigned nLen)
    {
        return base::_copy(pInBuf, nLen);
    }
    void Begin(short nCommand, char cVersion = SERVER_PACEKTVER)
    {
        base::_begin(nCommand, cVersion);
    }
    void End(void)
    {
        base::_end();
    }
   
    void SetBegin(short nCommand)
    {
        base::_SetBegin(nCommand);
    }
};

typedef InputPacket<ES_TCP_MAX_BUFFER>   ESInputPacket;
typedef OutputPacket<ES_TCP_MAX_BUFFER>  ESOutputPacket;
